home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / djgppzip / pubnames.shr / names2dos < prev    next >
Encoding:
Text File  |  1994-03-01  |  23.6 KB  |  800 lines

  1. #!/bin/sh
  2. # names2dos [-DEBUG | -d | -V | -L | -help ] directory_name
  3. trap 'rm -f $TMP $CHANGECONTENTS $CHANGECONTENTS_SED $CHANGENAMES_DIR $CHANGENAMES $AWK_SCRIPT; echo "$NAME received signal. Exiting." ; exit 1 '1 2 3 6 9 15
  4.  
  5. VERSION=" $Header: /users/bergman/Bin/Names2Dos/RCS/names2dos,v 2.1 1993/04/13 04:01:33 bergman Exp bergman $"
  6. NAME=`basename $0`
  7.  
  8. #
  9. #
  10.  
  11.  
  12. #  **********************************************************************
  13. #  *                                    *
  14. #  *    names2dos Copyright (c) 1993 Mark Bergman            *
  15. #  *                                    *
  16. #  *    This program is free software; you can redistribute it and/or    *
  17. #  *    modify it under the terms of the GNU General Public License as    *
  18. #  *    published by the Free Software Foundation; either version 2 of    *
  19. #  *    the License, or (at your option) any later version.        *
  20. #  *                                    *
  21. #  *    This program is distributed in the hope that it will be useful,    *
  22. #  *    but WITHOUT ANY WARRANTY; without even the implied warranty of    *
  23. #  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
  24. #  *    GNU General Public License for more details.            *
  25. #  *                                    *
  26. #  *    You should have received a copy of the GNU General Public    *
  27. #  *    License along with this program; if not, write to the Free    *
  28. #  *    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,    *
  29. #  *    USA.                                *
  30. #  *                                    *
  31. #  *                                    *
  32. #  *        Mark Bergman                        *
  33. #  *        bergman@panix.com                    *
  34. #  *        ...!{uunet,cmcl2}!panix!bergman                *
  35. #  *        718-855-9148                        *
  36. #  *                                    *
  37. #  **********************************************************************
  38.  
  39.  
  40. #
  41. #     This script is designed to walk through a directory tree and
  42. #     change filenames to conform to MS-DOS standards. It attempts
  43. #     to generate unique filenames, and will change all references
  44. #     to invalid names _within files_ to the newly created names.
  45. #     The script requires a modern version of awk--nawk or gnu awk
  46. #     
  47. #    The script creates one file, changelog, to record the
  48. #    changes made to the directory tree.
  49. #
  50. # The companion awk script takes a file or
  51. # directory name, with a path, and returns the original name
  52. # and a unique, DOS compatible name to stdout, in the format:
  53. #    path_long_names/files_long_names path_lon/files_lo
  54. # Unchanged names are _not_ returned by the awk script.
  55. #    
  56.  
  57. # Initialization
  58. AWK=nawk        # Command for "smart" awk, possibly nawk or gawk
  59. SED=gsed        # Command for sed. Gnu sed PREFERRED
  60. LOG=changes.log
  61. AWK_SCRIPT=/tmp/$NAME.$$.awk
  62. TMP=/tmp/$NAME.$$
  63. CHANGENAMES=/tmp/changenames.$$
  64. CHANGENAMES_DIR=/tmp/changenames.dir.$$
  65. CHANGECONTENTS=/tmp/changecontents.$$
  66. CHANGECONTENTS_SED=/tmp/changecontents.sed.$$
  67. DEBUG=FALSE
  68. DEVICES=FALSE
  69. # Get options.
  70. #
  71. while [ $# -ne 0 ]
  72. do
  73.   case $1 in
  74.     -DEBUG)
  75.     DEBUG=TRUE
  76.     shift;;
  77.     -d)
  78.     DEVICES=TRUE
  79.     shift;;
  80.     -help | -h | "-?")
  81.     echo ""
  82.     echo "Usage: $NAME [-DEBUG | -d | -V | -L | -help ] directory_name"
  83.     echo "$NAME will walk the directory tree and change all file and directory"
  84.     echo "names to conform to MS-DOS standards. Any references to invalid names"
  85.     echo "within files will also be changed."
  86.     echo ""
  87.     echo "Options:"
  88.     echo "    -DEBUG    Produce verbose output while processing and save"
  89.     echo "        intermediate files."
  90.     echo "    -d    DOS devices. Changes references to /dev devices (null,"
  91.     echo "        tty) to acceptable DOS versions (nul, con). This"
  92.     echo "        option will result in files that are incompatible"
  93.     echo "        under Unix."
  94.     echo "    -V    Version. Print the current version of $NAME."
  95.     echo "    -L    Limits. Print the limits of $NAME."
  96.     echo "    -help    Help. Display this message."
  97.     echo ""
  98.     echo "      A backup copy of the directory tree you plan to change should"
  99.     echo "      be made prior to running $NAME."
  100.     echo ""
  101.     exit 0;;
  102.     -V) 
  103.     VERSION=`echo $VERSION|$SED -e "s/^.*,v//" -e "s/Exp.*//"`
  104.     echo "${0} version: $VERSION"
  105.     # O.K., this is an ugly hack. I grep for the comment that identifies
  106.     # the version of the awk script, but grep will also return the line
  107.     # with the grep command itself! I must throw away the first line that
  108.     # grep receives, and only process the second.
  109.     AWK_VERSION=`grep AWK_SCRIPT_VERSION $0 | $SED -e "1d" -e "s/^.*,v//" -e "s/Exp.*//"`
  110.     echo "${0} awk script version: $AWK_VERSION"
  111.     exit 0;;
  112.     -L) 
  113.     echo "$NAME limits: system imposed limits on $SED, $AWK. Maximum"
  114.     echo "of 41 variations will be created to avoid collisions in the case"
  115.     echo "of non-unique names."
  116.     exit 0;;
  117.     -*) 
  118.     echo "Unrecognized option: $1."
  119.     echo "Usage: $NAME [-DEBUG | -d | -V | -L | -help ] directory_name"
  120.     exit 1;;
  121.        
  122.     *) 
  123.        break;;
  124.   esac
  125. done
  126.  
  127.  
  128. # Check for correct number of arguments (1)
  129. if [ $# -ne 1 ]
  130. then
  131.     echo "Usage: $NAME [-DEBUG | -d | -V | -L | -help ] directory_name"
  132.     exit
  133. fi
  134.  
  135. # Well, the arguments _look_ good...
  136.  
  137. ROOT=$1
  138. # Check to see if $ROOT is a sane choice
  139. if [ ! -d $ROOT -o ! -x $ROOT  -o ! -w $ROOT ]
  140. then
  141.     echo Usage: $NAME directory_name
  142.     echo "      $ROOT must be a directory where you have read, write,"
  143.     echo "      and execute (cd) permission"
  144.     exit 2
  145. fi
  146.  
  147. if [ ! -w . ]
  148. then
  149.     echo Usage: $NAME directory_name
  150.     echo "      You must have write permission in the currrent directory"
  151.     echo "      to create the $NAME log file."
  152.     exit 3
  153. fi
  154.  
  155. if [ $DEBUG = TRUE ]
  156. then
  157.     echo Writing awk script to $AWK_SCRIPT
  158. fi
  159.  
  160. # O.K., we have a reasonable ROOT, write the awk script into a
  161. # temporary file
  162. cat > $AWK_SCRIPT << 'E-O-AWK'
  163. #################################################################
  164. #                AWK SCRIPT BEGINS
  165. #################################################################
  166. # This awk script REQUIRES the "new" awk. It may be called
  167. # awk, nawk, or gawk on your particular system.
  168. #
  169. # awk script. Designed to be run by names2dos
  170. # script. This awk script will accept filenames output from
  171. # "find" and produce a paired list of the original filenames
  172. # and DOS naming convention acceptable filenames.
  173. # Files/directories that don't need to be changed are not
  174. # printed.
  175. # AWK_SCRIPT_VERSION: $Header: /users/bergman/Bin/Names2Dos/RCS/names2dos.awk,v 2.0 1993/04/11 23:36:01 bergman Exp $
  176. #
  177. #
  178. # Revision 1.0  1993/03/21  19:54:05  bergman
  179.  
  180. # Please send any comments/questions/bug fixes to:
  181. #    Mark Bergman
  182. #    bergman@panix.com
  183. #    ...{uunet,cmcl2}!panix!bergman
  184. #
  185. #
  186.  
  187. BEGIN { FS="/"    
  188.         NUMNAMES=0
  189.         VALIDCHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-_~!$"
  190.         NUMVALID=41
  191.         USEDNAMES[0]=""
  192.         }
  193. # Split each line at the slash (/)
  194. {
  195.     # For each component of the path, make a valid filename
  196.     # Only call filename2dos on the last component of each
  197.     # pathname
  198.     newname=""
  199.     for ( i = 1 ; i <= NF ; i++)
  200.         {
  201.             if ( i == NF )
  202.                 {
  203.                     # We are at the _last_ component
  204.                     # in the pathname
  205.                     newname=newname filename2dos($i)
  206.                 }
  207.             else
  208.                 {
  209.                 # We are somewhere in a multi-part path
  210.                     newname=newname $i "/"
  211.                 }
  212.         }
  213.  
  214.     # Check to see if we really had to change the name...
  215.     if ( $0 != newname )
  216.         {
  217.             # Yes, a new filename was created... Now check to
  218.             # see that it is really unique!
  219.     
  220.             # Set the "number of duplicates" counter to 0
  221.             numdupes=0
  222.             while (    CheckNameSpace(newname,USEDNAMES,NUMNAMES) == "FALSE" )
  223.             {
  224.                 # We have a duplicate name (otherwise we
  225.                 # wouldn't be here) so increment the numdupes
  226.                 # counter
  227.                 # numdupes is the index into the VALIDCHARS
  228.                 # array, pointing at a different character in
  229.                 # each attempt to generate a unique filename.
  230.  
  231.                 numdupes++
  232.  
  233.                 # Check to see if we've exhausted the
  234.                 # list of alternate characters for the last
  235.                 # letter in the basename without finding a
  236.                 # unique name. This would only happen in the
  237.                 # case where there are already 41 unique files
  238.                 # in the form
  239.                 #     xxxxxxxN
  240.                 # where N is a different character from the
  241.                 # set of VALIDCHARS for each filename. There
  242.                 # may be some MS-DOS acceptable characters
  243.                 # that I have ommitted from VALIDCHARS, but
  244.                 # who cares?
  245.  
  246.                 if ( numdupes == NUMVALID )
  247.                     {
  248.                         printf("No unique name has been generated for %s.\nRename %s manually.\n",$0,$0)
  249.                         exit(numdupes)
  250.                     }
  251.  
  252.                 # As long as we run into duplicate names,
  253.                 # change the last letter on the base of the
  254.                 # name to try to find a unique name
  255.  
  256.                 newname=ChangeName(newname,numdupes,VALIDCHARS)
  257.             }
  258.         NUMNAMES++
  259.         printf("%s %s\n",$0,newname)
  260.         }
  261.     else
  262.         {
  263.             # O.K., the supplied name fits the 8.3 naming
  264.             # scheme, but we still have to add it to the
  265.             # list of USEDNAMES to avoid future duplicates.
  266.             NUMNAMES++    # increment the number of unique names
  267.             USEDNAMES[NUMNAMES]=newname
  268.         }
  269. }
  270. END{}
  271.  
  272. function filename2dos(FiLeNaMe)
  273. {
  274. #    take a filename and make it dos-legal:
  275. #        name[.extension]
  276. #    where
  277. #        name    is 8 characters or less
  278. #                does not contain any illegal characters
  279. #    where
  280. #        extension
  281. #                is 3 characters of less
  282. #                does not contain any illegal characters
  283. #
  284. #     return a legal DOS filename
  285. #
  286. #    Initialization
  287.  
  288.     components=""
  289.     NAMEpart=""
  290.     DOSname=""
  291.     EXTENSIONpart=""
  292.     DOSextension=""
  293.     FILENAME=""
  294.  
  295. # Begin...
  296. #    Take given FiLeNaMe (possible mixed case) and change
  297. #    to an all upper-case "FILENAME"
  298.     FILENAME = changecase(FiLeNaMe,"upper")
  299.  
  300. #     If the first character in the filename is a "." make it an "_"
  301.     sub(/^\./,"_",FILENAME)
  302. #     If the last character in the filename is a "." make it an "._"
  303.     sub(/\.$/,"._",FILENAME)
  304.  
  305. #    Split the FILENAME into different components separated by periods
  306.     components=split(FILENAME,nameparts,".")
  307.  
  308. #    There will always be at least a name part
  309.  
  310.     NAMEpart=nameparts[1]
  311.  
  312.     if ( components == 1 )
  313.         {
  314.             DOSname=substr(NAMEpart,1,8)
  315.             gsub(/[     `@#%^&*()+={}\[\]:;"'<>,.?\/\\|]/,"-",DOSname)
  316.             # The above gsub attempts to remove all
  317.             # characters that are illegal in DOS filenames.
  318.             # This will probably fail miserably on true Posix
  319.             # 2.0 compliant 8-bit clean filenames. Tough luck.
  320.             # You can add high order characters, etc. to the
  321.             # above set, but I wanted to avoid the pain in the
  322.             # butt involved in making this a binary file as far
  323.             # as mail and downloading were concerned.
  324.         }
  325.  
  326.     if ( components == 2 )
  327.         {
  328.             EXTENSIONpart=nameparts[2]
  329.             DOSextension=substr(EXTENSIONpart,1,3)
  330.             gsub(/[     `@#%^&*()+={}\[\]:;"'<>,.?\/\\|]/,"-",DOSextension)
  331.  
  332.             DOSname=substr(NAMEpart,1,8)
  333.             gsub(/[ `!@#%^&*()+={}\[\]:;"'<>,.?\/\\|]/,"-",DOSname)
  334.             DOSname=DOSname "." DOSextension
  335.         }
  336.  
  337.     if ( components > 2 )
  338.         {
  339.         # Convert names in the form:
  340.         #        base.1.2.3.extension
  341.         # to:
  342.         #        base_1_2.ext
  343.  
  344.  
  345.             for ( j = 2 ; j < components ; j++)
  346.                 {
  347.                     if ( length(NAMEpart) <=6 )
  348.                         {
  349.                             NAMEpart=NAMEpart "_" nameparts[j]
  350.                         }
  351.                     else
  352.                         {
  353.                             NAMEpart=NAMEpart nameparts[j]
  354.                         }
  355.                 }
  356.             EXTENSIONpart=nameparts[j]
  357.             DOSextension=substr(EXTENSIONpart,1,3)
  358.             gsub(/[ `!@#%^&*()+={}\[\]:;"'<>,.?\/\\|]/,"-",DOSextension)
  359.  
  360.             DOSname=substr(NAMEpart,1,8)
  361.             gsub(/[ `!@#%^&*()+={}\[\]:;"'<>,.?\/\\|]/,"-",DOSname)
  362.             DOSname=DOSname "." DOSextension
  363.         }
  364.     return(DOSname)
  365. }
  366.  
  367. function CheckNameSpace(Newname,Convertnames,Numnames)
  368. {
  369.         # Check the list of new file names to see
  370.         # if the current name is a duplicate
  371.  
  372.         # Assume that the generated name passed to this
  373.         # routine is unique
  374.         Uniquename="TRUE"
  375.  
  376.         for ( j = 1 ; j <= Numnames ; j++ )
  377.             {
  378.                 # Loop through the list of all the names
  379.                 # we've generated so far.
  380.                 if ( Newname == Convertnames[j] )
  381.                     {
  382.                         Uniquename="FALSE"
  383.                         j = Numnames     # Exit the loop
  384.                      }
  385.              } 
  386.         if ( Uniquename=="TRUE" )
  387.             {
  388.                 # If we got through the list of all the
  389.                 # converted filenames and Newname is still
  390.                 # unique, add it to the list.
  391.                 Convertnames[j]=Newname
  392.             }
  393.         return(Uniquename)
  394. }
  395.  
  396.  
  397. function ChangeName(newname,numdupes,VALIDCHARS)
  398. {
  399.     # Given a name in the form
  400.     #    base.extension
  401.     # that is already DOS acceptable but is a duplicate of
  402.     # an existing name, change the last character in the
  403.     # base to try to create a new name.
  404.     # We will get clever enough to _add_ characters to the
  405.     # base if it is less than 8 chars
  406.     # This routine is not clever enough to pad out the
  407.     # extension to produce filenames that are fully 8.3 in an
  408.     # attempt to generate a unique name. At a worst case, 40
  409.     # filenames will be created. Mucking with the extension
  410.     # might be a bad idea, because so many extensions, like
  411.     # .c, have real meaning.
  412.  
  413.     # First of all, split up the full path+filename that we
  414.     # are given so that we can easily muck with just the
  415.     # filename.
  416.     Name2ChangePosition=split(newname,PATHCOMPONENTS,"/")
  417.     Name2Change=PATHCOMPONENTS[Name2ChangePosition]
  418.  
  419.     baselength=index(Name2Change,"\.")
  420.     if ( baselength > 0 )
  421.         {
  422.             # There is an extension that must be split
  423.             # from the base name
  424.             split(Name2Change,NAMEPARTS,"\.")
  425.             base = NAMEPARTS[1]
  426.             extension = NAMEPARTS[2]
  427.             baselength=length(base)
  428.             if ( baselength < 8 )
  429.                 {
  430.                     # If the base is less than 8 characters,
  431.                     # add the next character from the
  432.                     # VALIDCHARS set to the end of the base
  433.                     base=base substr(VALIDCHARS,numdupes,1)
  434.                 }
  435.             else
  436.                 {
  437.                     # The base is 8 characters. Substitute
  438.                     # the last character in the base with the
  439.                     # character from the VALIDCHARS set that
  440.                     # the numdupes index is pointing to.
  441.                     sub(/.$/,substr(VALIDCHARS,numdupes,1),base)
  442.                 }
  443.             # Re-build the complete filename
  444.             Name2Change=base "." extension
  445.         }
  446.     else
  447.         {
  448.             # There is no extension...Name2Change is the base
  449.             newnamelength=length(Name2Change)
  450.             if ( newnamelength < 8 )
  451.                 {
  452.                     Name2Change=Name2Change substr(VALIDCHARS,numdupes,1)
  453.                 }
  454.             else
  455.                 {
  456.                     sub(/.$/,substr(VALIDCHARS,numdupes,1),Name2Change)
  457.                 }
  458.         }
  459.  
  460.     # Now we've got another filename to pass back to
  461.     # the main routine and test for uniqueness again. We must
  462.     # rebuild the path+[new]filename.
  463.  
  464.     newname=PATHCOMPONENTS[1] # There is always at least 1 component
  465.                               # and this avoids adding a leading /
  466.     PATHCOMPONENTS[Name2ChangePosition]=Name2Change
  467.     for ( z= 2 ; z <= Name2ChangePosition ; z++ )
  468.         {
  469.             newname=newname "/" PATHCOMPONENTS[z]
  470.         }
  471.     return(newname)
  472. }
  473. function changecase(string,newcase)
  474. #
  475. #    Changes the case of the given string to the specified case
  476. #    Example:
  477. #        LINE = changecase($0,"upper")
  478.  
  479. {
  480.     
  481.     if ( newcase != "upper" && newcase != "lower" ) 
  482.         {
  483.         return(NULL)
  484.         }
  485.     else
  486.         {
  487.         RESULT = ""
  488.         Ucase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  489.         Lcase = "abcdefghijklmnopqrstuvwxyz"
  490.     
  491.         for(i=1;i <= length(string);i++)
  492.             {
  493.             if ( newcase == "upper" )
  494.                 {
  495.                 if( (cpos = index(Lcase,c = substr(string,i,1))) > 0)
  496.                     {
  497.                     c = substr(Ucase,cpos,1);
  498.                     }
  499.                 }
  500.             else
  501.                 {
  502.                 if( (cpos = index(Ucase,c = substr(string,i,1))) > 0)
  503.                     {
  504.                     c = substr(Lcase,cpos,1);
  505.                     }
  506.                 }
  507.             RESULT = RESULT c;
  508.             }
  509.         return (RESULT)
  510.         }
  511. }
  512. #################################################################
  513. #                AWK SCRIPT ENDS
  514. #################################################################
  515. E-O-AWK
  516.  
  517. # Run the find once to list Directory names and shove those
  518. # names through the awk script.
  519.  
  520. if [ $DEBUG = TRUE ]
  521. then
  522.     echo Collecting directory names from $ROOT
  523. fi
  524.  
  525. find $ROOT -type d -print | $AWK -f $AWK_SCRIPT > $TMP
  526. echo "$NAME run on $ROOT" > $LOG
  527.  
  528. # Run the value for ROOT through the awk script in case
  529. # that was one of the changed directory names.
  530.  
  531. NEWROOT=`echo $ROOT|$AWK -f $AWK_SCRIPT |$SED -e 's/^.* //' `
  532. # If $ROOT does not need to change, then NEWROOT will be null
  533. if [ "$NEWROOT" != "" ]
  534. then
  535.     ROOT=$NEWROOT
  536.     if  [ -d $ROOT -o -f $ROOT ]
  537.     then
  538.         #    That's it! My patience is exhausted!
  539.             echo ${NAME}: $ROOT must be removed to proceed.
  540.             exit 
  541.     fi
  542.     if [ $DEBUG = TRUE ]
  543.     then
  544.         echo $ROOT will change to $NEWROOT
  545.     fi
  546. fi
  547.  
  548. # If the TMP file isn't empty, there are directory names to change...
  549. while [  -s $TMP ]
  550. do
  551.     
  552.     #    This is a loop because the script will fail to rename
  553.     #    subdirectories of renamed directories. For example, given:
  554.     #        invalid_directory/bad_subdirectory/file1
  555.     #    the first iteration through the loop would generate a
  556.     #    script with the commands:
  557.     #        #!/bin/sh
  558.     #        mv -f invalid_directory invalid_
  559.     #        mv -f invalid_directory/bad_subdirectory invalid_/bad_subd
  560.     #    The second "mv" command would fail because the parent directory
  561.     #    invalid_directory no longer exists. The loop will change
  562.     #    directory names untill all names are DOS acceptable. Not too
  563.     #    clean, but easy.
  564.  
  565.     if [ $DEBUG = TRUE ]
  566.     then
  567.         echo Changing directory names
  568.     fi
  569.  
  570.     echo "" >> $LOG
  571.     echo "Recursive directory name changes:" >> $LOG
  572.     cat $TMP >> $LOG
  573.     
  574.     # Build the script to do the changes
  575.     echo "#!/bin/sh" > $CHANGENAMES_DIR
  576.  
  577.     # The following sed command:
  578.     #    substitutes the last <SPACE> followed by a
  579.     #    vaild MS-DOS filename for a <PLUS-SIGN>
  580.     #    followed by the same name.
  581.     #
  582.     #    Then substitute all other <SPACE>s (which
  583.     #    must be imbedded in the invalid filename)
  584.     #    with \<SPACE> to escape the meaning of
  585.     #    <SPACE> for the mv command.
  586.     #
  587.     #    Substitute a <SPACE> back in place of the
  588.     #    <PLUS SIGN> added earlier
  589.     #
  590.     #    escapes shell metacharacters: ( ) * ? $ ! ~ " 
  591.     #
  592.     #    adds "mv " to the beginning of each line
  593.     #
  594.  
  595.     $SED -e 's@\(.*\) \([A-Za-z0-9_\-~!\$/][0-9A-Za-z_\-~!\$\./]*\)@\1+\2@' -e 's@ @\\ @g' -e 's@\(.*\)+\([0-9A-Za-z_\-~!\$/][0-9A-Za-z_\-~!\$\./]*\)@\1 \2@' -e 's@\([][()*$!~"?]\)@\\\1@g' -e 's/^/mv -f /' $TMP >> $CHANGENAMES_DIR
  596.  
  597.     # Make the script executable
  598.     chmod +x $CHANGENAMES_DIR
  599.     
  600.     # Do the changes to directory names
  601.  
  602.     $CHANGENAMES_DIR 2> /dev/null
  603.     # There may be a lot of errors. Whenever a parent
  604.     # directory name is changed, all attempts to change child
  605.     # subdirectory names will fail. This is why error messages
  606.     # are thrown away and why the directory-name change
  607.     # section may be run repeatedly.
  608.  
  609.     if [ $DEBUG = FALSE ]
  610.     then
  611.         rm -f $TMP $CHANGENAMES_DIR
  612.     else
  613.         echo Collecting directory names again to search for additional invalid names
  614.     fi
  615.  
  616.     # Run the "find" again now that we've changed something.
  617.  
  618.     find $ROOT -type d -print | $AWK -f $AWK_SCRIPT > $TMP
  619. done
  620.  
  621.  
  622. # Run the find again to change file names, now that
  623. # directory names won't conflict under 8.3
  624.  
  625. if [ $DEBUG = TRUE ]
  626. then
  627.     echo Directory name changes complete
  628.     echo Collecting filenames
  629. fi
  630.  
  631. find $ROOT -type f -print | $AWK -f $AWK_SCRIPT > $TMP
  632. echo "" >> $LOG
  633. echo "File name changes:" >> $LOG
  634. cat $TMP >> $LOG
  635.  
  636. # Create a script to effect all the file name changes
  637. echo "#!/bin/sh" > $CHANGENAMES
  638.  
  639. # The following sed command:
  640. #  Replace <SPACE> with #;#
  641. #      #;# was chosen because it is approximately unique in a
  642. #      filename--both unlikely and difficult to put into a filename.
  643. #      
  644. #  Replace last #;# on the line w. <SPACE>
  645. #      The last <SPACE> (now a #;#) is always the separator
  646. #      between the original and converted pathnames.
  647. #
  648. #    Then substitute all other <SPACE>s (which
  649. #    must be imbedded in the invalid filename)
  650. #    with \<SPACE> to escape the meaning of
  651. #    <SPACE> for the mv command.
  652. #
  653. #    Substitute a <SPACE> back in place of the
  654. #    #;#  added earlier
  655. #
  656. #    escapes shell metacharacters: ( ) * ? $ ! ~ " 
  657. #
  658. #    adds "mv " to the beginning of each line
  659. #
  660.  
  661. $SED -e 's@ @#;#@g' -e 's@#;#\([^#;#]*\)$@ \1@' -e 's@#;#@\\ @g' -e 's@\([][()*$!~"?]\)@\\\1@g' -e 's/^/mv -f /' $TMP >> $CHANGENAMES
  662.  
  663.  
  664. # Simultaneously, we are building a sed script to change the
  665. # contents of any files that refer to file names
  666. # that have been altered. The following command just takes all
  667. # the filenames that will be changed and strips the paths
  668. # away. The awk script output in the TMP file in the form:
  669. #     long/non_DOS-useable/path+file.name long/non_DOS-u/path+fil.nam
  670. # becomes:
  671. #     path+file.name path+fil.nam
  672. #
  673. #  The following 4 sed commands create another sed file,
  674. #  CHANGECONTENTS_SED, which is used to change the contents of files in
  675. #  the tree. Each sed command takes the output from the awk script, in the
  676. #  form:
  677. #  
  678. #      Original/Bad/Path/and/Non-DOS-filename Good/Path/and/FILENAME.DOS
  679. #  
  680. #  and builds a slightly different sed expression for each entry. The 4
  681. #  different sed lines are necessary because the given Non-DOS-filename
  682. #  may be a subset of many filenames.  For example, if the name in
  683. #  question is "Makefile" there may also be "Makefile.fonts",
  684. #  "Makefile.install", etc. If the sed command changed all instances of
  685. #  "Makefile" to "MAKEFILE", then no instances of "Makefile.fonts" would
  686. #  be found.
  687. #  
  688. #  The sed commands each work in the following sequence:
  689. #  
  690. #  Replace <SPACE> with #;#
  691. #      #;# was chosen because it is approximately unique in a
  692. #      filename--both unlikely and difficult to put into a filename.
  693. #      
  694. #  Replace last #;# on the line w. <SPACE>
  695. #      The last <SPACE> (now a #;#) is always the separator
  696. #      between the original and converted pathnames.
  697. #  
  698. #  Delete initial path, leaving only 1st filename
  699. #  
  700. #  Delete 2nd path up to 2nd filename
  701. #  
  702. #  Escape sed metacharacters
  703. #      Put a \ before [ ] \ / . * ^ $    
  704. #  
  705. #  Following commands turn Filename1 Filename2 into a sed command
  706. #      Put s/ at the beginning of the line
  707. #      Put /\1 between the two filenames
  708. #  
  709. #  This stage differs slightly for each sed line. Here, the original
  710. #  filename is surrounded by regular expressions to limit how it is found
  711. #  in a line. The regular expressions (in order) are:
  712. #      \([     <>:\\\/][     <>:\\\\\\/]*\)ORIGINAL_FILENAME\([     <>:\\\/][ <>:\\\\\\/]*\)
  713. #      ^ORIGINAL_FILENAME\([     <>:\\\/][     <>:\\\\\\/]*\)
  714. #      \([     <>:\\\/][     <>:\\\\\\/]*\)ORIGINAL_FILENAME$
  715. #      \<ORIGINAL_FILENAME\>
  716. #  Note that the sed built-in regex delimiter pair \< \> is used last.
  717. #  Because many filenames use periods, the idea is to delay matching names
  718. #  delimited by periods until other combinations have been used.
  719. #  
  720. #  Put \2/g after the 2nd filename
  721. #  
  722. #  Convert all #;# back to <SPACE>
  723. #
  724.  
  725. $SED -e 's/ /#;#/g' -e 's/#;#\([^#;#]*\)$/ \1/' -e 's@^.*/\(.*\) @\1 @' -e 's@ .*/@ @' -e 's@\([][\.\*\$\^]\)@\\\1@g' -e 's@^@s/@' -e 's@ @/\\1@' -e 's@\/\(.*\)\/@\/\\([     <>:\\\\\\/][     <>:\\\\\\/]*\\)\1\\([     <>:\\\\\\/][     <>:\\\\\\/]*\\)\/@' -e 's@$@\\2/g@' -e 's/#;#/ /g' $TMP > $CHANGECONTENTS_SED
  726.  
  727. $SED -e 's/ /#;#/g' -e 's/#;#\([^#;#]*\)$/ \1/' -e 's@^.*/\(.*\) @\1 @' -e 's@ .*/@ @' -e 's@\([][\.\*\$\^]\)@\\\1@g' -e 's@^@s/@' -e 's@ @/@' -e 's@\/\(.*\)\/@\/^\1\\([     <>:\\\\\\/][     <>:\\\\\\/]*\\)\/@' -e 's@$@\\1/g@' -e 's/#;#/ /g' $TMP >> $CHANGECONTENTS_SED
  728.  
  729. $SED -e 's/ /#;#/g' -e 's/#;#\([^#;#]*\)$/ \1/' -e 's@^.*/\(.*\) @\1 @' -e 's@ .*/@ @' -e 's@\([][\.\*\$\^]\)@\\\1@g' -e 's@^@s/@' -e 's@ @/\\1@' -e 's@\/\(.*\)\/@\/\\([     <>:\\\\\\/][     <>:\\\\\\/]*\\)\1$\/@' -e 's@$@/g@' -e 's/#;#/ /g' $TMP >> $CHANGECONTENTS_SED
  730.  
  731. $SED -e 's/ /#;#/g' -e 's/#;#\([^#;#]*\)$/ \1/' -e 's@^.*/\(.*\) @\1 @' -e 's@ .*/@ @' -e 's@\([][\.\*\$\^]\)@\\\1@g' -e 's@^@s/@' -e 's@ @/@' -e 's@^.*/\(.*\) @\\<\1\\> @' -e 's@$@/g@' -e 's/#;#/ /g' $TMP >> $CHANGECONTENTS_SED
  732.  
  733. if [ $DEVICES = TRUE ]
  734. then
  735.     echo "s@/dev/null@/dev/nul@g" >> $CHANGECONTENTS_SED
  736.     echo "s@/dev/tty@/dev/con@g" >> $CHANGECONTENTS_SED
  737. fi
  738.  
  739.  
  740. echo "#!/bin/sh" > $CHANGECONTENTS
  741. cat >> $CHANGECONTENTS << E-O-CAT
  742. $SED -f $CHANGECONTENTS_SED \$1 > \$\$
  743. # perform a minor sanity check...
  744. cmp -s \$1 \$\$
  745. if [ \$? -eq 1 ]
  746. then
  747.     # if the sed command had any effect...
  748.     mv -f \$\$ \$1
  749.     echo "\$1 contents changed" 
  750. fi
  751. rm -f \$\$
  752. E-O-CAT
  753.  
  754. chmod +x $CHANGENAMES
  755.  
  756. if [ $DEBUG = TRUE ]
  757. then
  758.     echo Effecting file name changes
  759. fi
  760.  
  761. # This should not generate any errors. If it does, report
  762. # and log the error and switch to DEBUG mode to save the
  763. # file that produced the error.
  764.  
  765. $CHANGENAMES 2>> $LOG 1>> $LOG
  766. if [ $? != 0 ]
  767. then
  768.     echo "ERROR in changnames. See precceding line." >> $LOG
  769.     echo "ERROR in changnames. Switching to DEBUG mode to save $CHANGENAMES" 
  770.     echo "Please examine $LOG for details on the error."
  771.     DEBUG=TRUE
  772. fi
  773.  
  774. chmod +x $CHANGECONTENTS
  775.  
  776. if [ $DEBUG = TRUE ]
  777. then
  778.     echo Effecting changes to the contents of files. This may take a while.
  779.     if [ $DEVICES = TRUE ]
  780.     then
  781.         echo Devices option in effect. 
  782.     fi
  783. fi
  784.  
  785. echo "" >> $LOG
  786. if [ $DEVICES = TRUE ]
  787. then
  788.     echo "Devices option in effect. Files referring to /dev/tty or /dev/null will change." >> $LOG
  789. fi
  790. echo "File contents changes:" >> $LOG
  791. echo "" >> $LOG
  792. find $ROOT -type f -exec $CHANGECONTENTS {} \; >> $LOG
  793. if [ $DEBUG = FALSE ]
  794. then
  795.     rm -f $TMP $CHANGECONTENTS $CHANGECONTENTS_SED $CHANGENAMES_DIR $CHANGENAMES $AWK_SCRIPT
  796. else
  797.     echo "Leaving:"
  798.     echo "    $CHANGECONTENTS $CHANGECONTENTS_SED $CHANGENAMES_DIR $CHANGENAMES $TMP $AWK_SCRIPT"
  799. fi
  800.